/*
********************************************************************************
*
*	name : dwt delay
*	file : bsp_dwt.c
********************************************************************************
*/
#include "bsp.h"

uint32_t clks_per_us;
extern uint32_t SystemClockFrequency;
#define SystemCoreClock SystemClockFrequency

/*******************************************************************************
* @brief  bsp_delay_init
* \param[in] none
* \retval: none
*******************************************************************************/
void bsp_delay_init(void)
{
	intx_alloc();
	
	intx_disable();
	
    //Enable Cortex DWT CYCCNT reg
    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; 
    DWT->CYCCNT = 0;
    DWT->CTRL        |= DWT_CTRL_CYCCNTENA_Msk;
	
    intx_enable();
	
    //clks per us
    clks_per_us = (SystemCoreClock / 1000000);
}

/*******************************************************************************
* @brief  bsp_dwt_check
*         IDE may disable the conter when debug quit.
*         call this function in main-loop, ensure the timer keep runing. 
* \param[in] none
* \retval: none
*******************************************************************************/
void bsp_dwt_check(void)
{
    if(CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk)
    {
        if(DWT->CTRL & DWT_CTRL_CYCCNTENA_Msk)
        {
            return;
        }
    }
    
    bsp_delay_init();
}

/*******************************************************************************
* @brief  bsp_delay_ms
* \param[in] ms delay
* \retval: none
*******************************************************************************/
void bsp_delay_ms(uint32_t ms)
{
	bsp_delay_us(1000*ms);
}

/*******************************************************************************
* @brief  bsp_delay_us
*         Global variable is readonly. This function can be called in multi-task.
* \param[in] us delay
* \retval: none
*******************************************************************************/
void bsp_delay_us(uint32_t us)
{
    uint32_t tCnt, tDelayCnt;
	uint32_t tStart;
	
	bsp_dwt_check();		// 8clk + 清流水线
	
	tStart = DWT->CYCCNT;	// 1                        
	tCnt = 0;				// 1 clk
	tDelayCnt = us * clks_per_us - 14;	  // 4clk                		      

	while(tCnt < tDelayCnt)
	{
    	bsp_dwt_check();
		tCnt = DWT->CYCCNT - tStart;   //overflow is ok
	}
}

/*******************************************************************************
* @brief  bsp_cpu_clks_get
* \param[in] none
* \retval: clk now
*******************************************************************************/
uint32_t bsp_cpu_clks_get(void)
{
    return DWT->CYCCNT;
}

/*******************************************************************************
* @brief  bsp_clks_to_us
* \param[in] clks
* \retval: us
*******************************************************************************/
uint32_t bsp_clks_to_us(uint32_t clks)
{
    return (clks + (clks_per_us >> 1)) / clks_per_us;
}
